//
//  FNMockManager.m
//  MockServer
//
//  Created by caoyq on 2021/2/9.
//

#import "FNMockManager.h"
#import "FNMockURLProtocol.h"
#import <objc/runtime.h>

static NSString *const kIsMockKey   = @"isMockKey";
static NSString *const kMapTableKey = @"mapTableKey";
static NSString *const kDomainKey   = @"domainKey";
static NSString *const kMapPathKey  = @"mapPathKey";

@implementation FNMockManager

+ (instancetype)shareInstance {
    static FNMockManager *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
    });
    return instance;
}

- (void)initConfig {
    // 创建公用的队列
    self.delegateQueue = [[NSOperationQueue alloc] init];
    self.delegateQueue.name = @"com.fmmockmanager.queue";
    self.delegateQueue.maxConcurrentOperationCount = 10;
    
    [self readLocalConfig];
    if (self.isMock) {
        [self startMock];
    }
}

/// 开启 mock，注册监控
- (void)startMock {
    [NSURLProtocol registerClass:[FNMockURLProtocol class]];
    // 通过替换 NSURLSessionConfiguration 中的 protocolClasses 方法，来实现用自定义的 protocol 监控
    // sessionWithConfiguration 方法构建的 session 请求
    [FNMockManager registerSwizzle];
}

/// 关闭 mock，取消监控
- (void)stopMock {
    [NSURLProtocol unregisterClass:[FNMockURLProtocol class]];
    [FNMockManager unregisterSwizzle];
}

#pragma mark - 替换 NSURLSessionConfiguration 中的 protocolClasses 方法

+ (void)registerSwizzle {
    Class cls = NSClassFromString(@"__NSCFURLSessionConfiguration") ?: NSClassFromString(@"NSURLSessionConfiguration");
    [self swizzleSelector:@selector(protocolClasses) fromClass:cls toClass:[self class]];
}

+ (void)unregisterSwizzle {
    Class cls = NSClassFromString(@"__NSCFURLSessionConfiguration") ?: NSClassFromString(@"NSURLSessionConfiguration");
    [self swizzleSelector:@selector(protocolClasses) fromClass:cls toClass:[self class]];
}

+ (void)swizzleSelector:(SEL)selector fromClass:(Class)original toClass:(Class)target {
    Method originalMethod = class_getInstanceMethod(original, selector);
    Method targetMethod = class_getInstanceMethod(target, selector);
    if (!originalMethod || !targetMethod) {
        [NSException raise:NSInternalInconsistencyException format:@"Couldn't load NEURLSessionConfiguration."];
    }
    method_exchangeImplementations(originalMethod, targetMethod);
}

- (NSArray *)protocolClasses {
    return @[[FNMockURLProtocol class]];
}

#pragma mark - W + R

/// 读取本地的配置信息
- (void)readLocalConfig {
    NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
    self.isMock = [def boolForKey:kIsMockKey];
    self.mapTable = [def dictionaryForKey:kMapTableKey];
    self.domain = [def stringForKey:kDomainKey];
    self.mapPath = [def stringForKey:kMapPathKey];
    [def synchronize];
}

/// 保存配置信息到本地
- (void)saveConfigToLocal {
    NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
    [def setBool:self.isMock forKey:kIsMockKey];
    [def setValue:self.mapTable forKey:kMapTableKey];
    [def setValue:self.domain forKey:kDomainKey];
    [def setValue:self.mapPath forKey:kMapPathKey];
    [def synchronize];
}

@end
